package com.flexrrb.controls
{
	import com.flexrrb.events.PrintScreenEvent;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	
	import mx.core.Application;
	import mx.core.Container;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import mx.graphics.ImageSnapshot;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;
	
	
	[Style(name="areaColor", type="Number", format="Color", inherit="no")]
	[Style(name="areaAlpha", type="Number", inherit="no")]
	
	/*broadcast before entering capturing phase*/
	[Event(name="beginCapturing", type="com.flexrrb.events.PrintScreenEvent")]
	
	/*broadcast during capturing phase*/
	[Event(name="capturing", type="com.flexrrb.events.PrintScreenEvent")]
	
	/*broadcast after capturing phase*/
	[Event(name="captured", type="com.flexrrb.events.PrintScreenEvent")]
	
	public class PrintScreen extends Container
	{
		private var _baseComponent:UIComponent;
		private var baseComponentAssigned:Boolean;
		
		private var _status:String;
		private var _startingPoint:Point;
		private var _showOverlay:Boolean = true;
		
		private var _areaColor:uint;
		private var _areaAlpha:Number;
		
		private static var classConstructed:Boolean = constructClass();
		
		private static function constructClass():Boolean
		{
			var selector:CSSStyleDeclaration = StyleManager.getStyleDeclaration("PrintScreen");
			if(!selector)
			{
				selector = new CSSStyleDeclaration();
			}
			
			selector.defaultFactory = function():void
			{
				this.areaColor = 0xFCD116;
				this.areaAlpha = 0.5;
				this.visibleBackgroundAlpha = 0.2;
				this.backgroundColor = 0x333333;
			}
			
			
			
			StyleManager.setStyleDeclaration("PrintScreen", selector, false);
			
			return true;
		}
		
		
		public function PrintScreen()
		{
			this.visible = false;
			this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete, false, 0, true);
		}
		
		override public function styleChanged(styleProp:String):void
		{
			super.styleChanged(styleProp);
			if(styleProp)
			{
				if(styleProp == "areaAlpha")
				{
					this._areaAlpha = this.getStyle("areaAlpha") as Number;
				}
				else if(styleProp == "areaColor")
				{
					this._areaColor = this.getStyle("areaColor") as uint;
				}
			}
		}
		
		private function onCreationComplete(event:FlexEvent):void
		{
			this._areaAlpha = this.getStyle("areaAlpha") as Number;
			this._areaColor = this.getStyle("areaColor") as uint;
			
			Application.application.systemManager.addChild(this);
			baseComponent = Application.application as UIComponent;
		}
		
		public function get showOverlay():Boolean
		{
			return _showOverlay;
		}
		
		public function set showOverlay(value:Boolean):void
		{
			_showOverlay = value;
		}
		
		public function get baseComponent():UIComponent
		{
			return _baseComponent;
		}
		
		public function set baseComponent(value:UIComponent):void
		{
			if(value)
			{
				baseComponentAssigned = true;
				this._baseComponent = value;
				invalidateSize();
			}
		}
		
		override protected function measure():void
		{
			super.measure();
			
			if(baseComponentAssigned)
			{
				baseComponentAssigned = false;
				this.width = baseComponent.width;
				this.height = baseComponent.height;
			}
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
		} 
		
		public function start():void
		{
			if(baseComponent)
			{
				dispatchEvent(new PrintScreenEvent(PrintScreenEvent.BEGIN_CAPTURING_EVENT));
				this.visible = true;
				if(_showOverlay)
				{
					this.setStyle("backgroundAlpha", this.getStyle("visibleBackgroundAlpha"));
				}
				else
				{
					this.setStyle("backgroundAlpha", 0);	
				}
				
				this.addEventListener(MouseEvent.MOUSE_MOVE, drawPrintArea, false, 0, true);
				this.addEventListener(MouseEvent.MOUSE_DOWN, prepareScreenShot, false, 0, true);
				this.addEventListener(MouseEvent.MOUSE_UP, takeScreenShot, false, 0, true);
			}
		}
		
		private function exit(event:KeyboardEvent):void
		{
			if(event.keyCode == Keyboard.ESCAPE)
			{
				cleanup();
			}
		}
		
		private function cleanup():void
		{
			this.removeEventListener(MouseEvent.MOUSE_MOVE, drawPrintArea, false);
			this.removeEventListener(MouseEvent.MOUSE_DOWN, prepareScreenShot, false);
			this.removeEventListener(MouseEvent.MOUSE_UP, takeScreenShot, false);
			this.removeEventListener(KeyboardEvent.KEY_UP, exit, false);
			this.graphics.clear();
			this.visible = false;
		}
		
		private function prepareScreenShot(event:MouseEvent):void
		{
			dispatchEvent(new PrintScreenEvent(PrintScreenEvent.CAPTURING_EVENT));
			this.removeEventListener(MouseEvent.MOUSE_DOWN, prepareScreenShot);
		}
		
		private function drawPrintArea(event:MouseEvent):void
		{
			if(!event.buttonDown)
				return;
			
			if(!_startingPoint)
			{
				_startingPoint = new Point(this.mouseX, this.mouseY);
			}
			else
			{
				this.graphics.clear();
				this.graphics.beginFill(_areaColor, _areaAlpha);
				this.graphics.drawRect(_startingPoint.x, _startingPoint.y, this.mouseX - _startingPoint.x, this.mouseY - _startingPoint.y);
				this.graphics.endFill();
			}
		}
		
		private function takeScreenShot(event:MouseEvent):void
		{
			if(!_startingPoint)
				return;
				
			var rect:Rectangle = new Rectangle(_startingPoint.x, _startingPoint.y, this.mouseX - _startingPoint.x, this.mouseY - _startingPoint.y);
			var matrix:Matrix = new Matrix();
			
			matrix.translate(_startingPoint.x, _startingPoint.y);
			
			this._startingPoint = null;
			
			var bitmapData:BitmapData = ImageSnapshot.captureBitmapData(baseComponent, null, 
					new ColorTransform(), null, rect, true);
			
			var newBitmapData:BitmapData = new BitmapData(rect.width, rect.height);
			newBitmapData.copyPixels(bitmapData, rect, new Point(0, 0));
			
			var bitmap:Bitmap = new Bitmap(newBitmapData);
			
			this.graphics.clear();
			
			cleanup();
			dispatchEvent(new PrintScreenEvent(PrintScreenEvent.CAPTURED_EVENT, bitmap));
			
		}
		
	}
}